#pragma once
#include <cstdlib> 
#include <unistd.h>
#include<string>
#include <sys/wait.h>
#include "task.hpp"
class channel{

 public:
   channel(pid_t pid,int fd):_pid(pid),_fd(fd){
      _channel_name="[子进程:"+to_string(_pid)+"---管道："+to_string(_fd)+"]";
   }
    bool send(int code){

      int n = write(_fd, &code, sizeof(code));
        if (n == sizeof(code))  return true;
         else return false;      
    }
    void channel_close() {
        close(_fd);
    }
    void channel_wait(){
      pid_t wp=waitpid(_pid,nullptr,0);
    }
     string get_name(){
        return _channel_name;
     }

   ~channel(){}

 private:
   pid_t _pid;
   int _fd;
   string _channel_name;
};

class channel_set
{
  public:

     channel_set(){}
       void Insert(pid_t pid ,int fd){
           _cls.emplace_back(pid,fd);
       }

       channel& Select(){
          auto &c=_cls[_next];
          _next++;
          _next%=_cls.size();
          return c;
       }

       void close_channels(){
         for(int i=0;i<_cls.size();i++){
            _cls[i].channel_close();
         }
      }

       void wait_subprocess(){
      for(int i=0;i<_cls.size();i++){
           _cls[i].channel_wait();
         }
       }
     void candw(){
      for(int i=_cls.size()-1;i>=0;i--){
            _cls[i].channel_close();
               _cls[i].channel_wait();
              
            }
   
      //  for(int i=0;i<_cls.size();i++){
      //     _cls[i].channel_close();
      //        _cls[i].channel_wait();
            
      //     }

        
     }

         void sub_close_allw(){
         for(int i=0;i<_cls.size();i++){
            _cls[i].channel_close();
             }
         }
     
  private:
   vector<channel> _cls;
   int _next;
};

class propool{
 public:
      propool(int x):_pipesize(x){
       _tt.Register(&PrintLog);
       _tt.Register(& Download);
       _tt.Register(&Upload); 
      }
       void work(int fd){
        while(1){
          int code;
           int n= read(fd,&code,sizeof(code));
           if(n>0){
                if(n!=sizeof(code)) continue;
                cout<<"子进程:"<<getpid()<<" 获得的任务码："<<code<<endl;
                _tt.Excute(code);
           }
           else if(n==0) {
            cout<<"子进程:"<<getpid()<<" 正常退出"<<endl;
                break;
           }
           else {
            cout<<"读取错误"<<endl;
              break;
           }
        }
       }
      bool Start(){
        for(int i=1;i<=_pipesize;i++){
        int fd[2];
        int n=pipe(fd);
        if(n<0)  return false;
        pid_t pid=fork();
        if(pid<0) return false;
        else if(pid==0){
          //在这之前把继承的父进程的所有写端关掉(这里并不会把自己的写端给关掉；因为写时拷贝）：
         // _ct.sub_close_allw();
           close(fd[1]);
           work(fd[0]);
           exit(0);

        }
        else{
            close(fd[0]);
            _ct.Insert(pid,fd[1]);
        }
        }
        return 1;
      }
       
     void run(){
      int code= _tt.getcode();
        cout<<"父进程发布任务，任务码："<<code<<endl;
        auto&c=_ct.Select();
        cout<<"父进程选择的管道："<<c.get_name()<<endl;
        cout<<"将要把任务分配给子进程执行"<<endl;
        c.send(code);

     }
       void stop(){
          //  cout<<"即将关闭管道"<<endl;
          //  _ct.close_channels();
          //  cout<<"父进程已经关闭所有管道"<<endl;
          //  cout<<"即将回收所有子进程"<<endl;
          //  _ct.wait_subprocess();
          //  cout<<"所有子进程已完成回收"<<endl;
          _ct.candw();


       }
      ~propool(){}
 private:
 task_set _tt;
 channel_set _ct;
  int _pipesize;
};
